home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / pgp20src.zip / LANGUAGE.C < prev    next >
C/C++ Source or Header  |  1992-09-03  |  9KB  |  414 lines

  1. /*
  2.  *    language.c - Foreign language translation for PGP
  3.  *    Finds foreign language "subtitles" for English phrases 
  4.  *    in external foriegn language text file.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include "usuals.h"
  12. #include "fileio.h"
  13. #include "language.h"
  14. #include "pgp.h"
  15.  
  16. #define SUBTITLES_FILE    "language.txt"
  17. #define LANG_INDEXFILE    "language.idx"
  18.  
  19. #define    STRBUFSIZE        2048
  20.  
  21. char language[16] = "en";    /* The language code, defaults to English */
  22. static char    *strbuf;
  23. static char    lang[16];    /* readstr sets this to the language id of the msg it last read */
  24. static int    subtitles_available = 0;
  25. static int line = 0;
  26. /*    subtitles_available is used to determine if we know whether the special
  27.     subtitles_file exists.  subtitles_available has the following values:
  28.     0  = first time thru, we don't yet know if subtitles_file exists.
  29.     1  = we have already determined that subtitles_file exists.
  30.     -1 = we have already determined that subtitles_file does not exist.
  31. */
  32.  
  33. #define    NEWLINE        0
  34. #define    COMMENT        1
  35. #define    INSTRING    2
  36. #define    ESCAPE        3
  37. #define    IDENT        4
  38. #define    DONE        5
  39. #define    ERROR        6
  40. #define    ERR1        7
  41.  
  42. /* Look for and return a quoted string from the file.
  43.  * If nlabort is true, return failure if we find a blank line
  44.  * before we find the opening quote.
  45.  */
  46. static char    *
  47. readstr (FILE *f, char *buf, int nlabort)
  48. {    int        c, d;
  49.     char *p = buf;
  50.     int state = NEWLINE;
  51.     int i = 0;
  52.     
  53.     while ((c = getc(f)) != EOF)
  54.     {
  55.         if (c == '\r')
  56.             continue;
  57.         /* line numbers are only incremented when creating index file */
  58.         if (line && c == '\n')
  59.             ++line;
  60.         switch (state)
  61.         {
  62.             case NEWLINE:
  63.                 switch(c)
  64.                 {
  65.                     case '#': state = COMMENT; break;
  66.                     case '"': state = INSTRING; break;
  67.                     case '\n':
  68.                         if (nlabort)
  69.                         {    *buf = '\0';
  70.                             return(buf);
  71.                         }
  72.                     default:
  73.                         if (i == 0 && isalnum(c))
  74.                         {
  75.                             state = IDENT;
  76.                             lang[i++] = c;
  77.                             break;
  78.                         }
  79.                         if (!isspace(c))
  80.                         {
  81.                             fprintf(stderr, "language.txt:%d: syntax error\n", line);
  82.                             state = ERROR;
  83.                         }
  84.                 }
  85.                 break;
  86.             case COMMENT:
  87.                 if (c == '\n')
  88.                     state = NEWLINE;
  89.                 break;
  90.             case INSTRING:
  91.                 switch(c)
  92.                 {
  93.                     case '\\': state = ESCAPE; break;
  94.                     case '"': state = DONE; break;
  95.                     default: *p++ = c;
  96.                 }
  97.                 break;
  98.             case ESCAPE:
  99.                 switch (c)
  100.                 {
  101.                     case 'n':    *p++ = '\n';    break;
  102.                     case 'r':    *p++ = '\r';    break;
  103.                     case 't':    *p++ = '\t';    break;
  104.                     case 'e':    *p++ = '\033';    break;
  105.                     case 'a':    *p++ = '\007';    break;
  106.                     case '#':
  107.                     case '"':
  108.                     case '\\':    *p++ = c; break;
  109.                     case '\n':    break;
  110.                     case '0':
  111.                             d = 0;
  112.                             while ((c = fgetc(f)) >= '0' && c <= '7')
  113.                                 d = 8 * d + c - '0';
  114.                             *p++ = d;
  115.                             ungetc(c, f);
  116.                             break;
  117.                     default:
  118.                             fprintf(stderr, "language.txt:%d: illegal escape sequence: '\\%c'\n", line, c);
  119.                             break;
  120.                 }
  121.                 state = INSTRING;
  122.                 break;
  123.             case IDENT:        /* language identifier */
  124.                 if (c == ':') {
  125.                     state = NEWLINE;
  126.                     break;
  127.                 }
  128.                 if (c == '\n' && strncmp(lang, "No translation", 14) == 0)
  129.                 {
  130.                     i = 0;
  131.                     state = NEWLINE;
  132.                     break;
  133.                 }
  134.                 lang[i++] = c;
  135.                 if (i == 15 || !isalnum(c) && !isspace(c))
  136.                 {
  137.                     lang[i] = '\0';
  138.                     fprintf(stderr, "language.txt:%d: bad language identifier: '%s'\n", line, lang);
  139.                     state = ERROR;
  140.                     i = 0;
  141.                 }
  142.                 break;
  143.             case DONE:
  144.                 if (c == '\n')
  145.                 {
  146.                     lang[i] = '\0';
  147.                     *p = '\0';
  148.                     return(buf);
  149.                 }
  150.                 if (!isspace(c))
  151.                 {
  152.                     fprintf(stderr, "language.txt:%d: extra characters after '\"'\n", line);
  153.                     state = ERROR;
  154.                 }
  155.                 break;
  156.             case ERROR:
  157.                 if (c == '\n')
  158.                     state = ERR1;
  159.                 break;
  160.             case ERR1:
  161.                 state = (c == '\n' ? NEWLINE : ERROR);
  162.                 break;
  163.         }
  164.     }
  165.     if (state != NEWLINE)
  166.         fprintf(stderr, "language.txt: unexpected EOF\n");
  167.     return(NULL);
  168. }
  169.  
  170. #ifdef TEST
  171. main()
  172. {
  173.     char buf[2048];
  174.  
  175.     line = 1;
  176.     while (readstr(stdin, buf, 0)) {
  177.         printf("\nen: <%s>\n", buf);
  178.         while (readstr(stdin, buf, 1) && *buf != '\0')
  179.             printf("%s: <%s>\n", lang, buf);
  180.     }
  181.     exit(0);
  182. }
  183. #else
  184.  
  185. static struct indx_ent {
  186.     word32    crc;
  187.     long    offset;
  188. } *indx_tbl = NULL;
  189.  
  190. static int max_msgs = 0;
  191. static int nmsg = 0;
  192.  
  193. static FILE *langf;
  194.  
  195. static void init_lang();
  196. static int make_indexfile(char *);
  197. word32 crcupdate(byte, word32);
  198. void init_crc();
  199.  
  200. /*
  201.  * uses 24-bit CRC function from armor.c
  202.  */
  203. static word32
  204. message_crc(char *s)
  205. {
  206.     word32 crc = 0;
  207.  
  208.     while (*s)
  209.         crc = crcupdate(*s++, crc);
  210.     return(crc);
  211. }
  212.  
  213. /*
  214.  * lookup file offset in indx_tbl
  215.  */
  216. static long
  217. lookup_offset(word32 crc)
  218. {
  219.     int i;
  220.     
  221.     for (i = 0; i < nmsg; ++i)
  222.         if (indx_tbl[i].crc == crc)
  223.             return(indx_tbl[i].offset);
  224.     return(-1);
  225. }
  226.  
  227.  
  228. /*
  229.  * return foreign translation of s
  230.  */
  231. char *
  232. PSTR (char *s)
  233. {
  234.     long filepos;
  235.  
  236.     if (subtitles_available == 0)
  237.         init_lang();
  238.     if (subtitles_available < 0)
  239.         return(s);
  240.  
  241.     filepos = lookup_offset(message_crc(s));
  242.     if (filepos == -1)
  243.         return(s);
  244.     else
  245.     {
  246.         fseek(langf, filepos, SEEK_SET);
  247.         readstr(langf, strbuf, 1);
  248.     }
  249.  
  250.     if (strbuf[0] == '\0')
  251.         return(s);
  252.  
  253.     for (s = strbuf; *s; ++s)
  254.         *s = EXT_C(*s);
  255.     return(strbuf);
  256. }
  257.  
  258.  
  259. static struct {
  260.     long lang_fsize;    /* size of language.txt */
  261.     char lang[16];        /* language identifier */
  262.     int nmsg;            /* number of messages */
  263. } indx_hdr;
  264.  
  265.  
  266. /*
  267.  * initialize the index table: read it from language.idx or create
  268.  * a new one and write it to the index file. A new index file is
  269.  * created if the language set in config.pgp doesn't match the one
  270.  * in language.idx or if the size of language.txt has changed.
  271.  */
  272. static void
  273. init_lang()
  274. {
  275.     char indexfile[MAX_PATH];
  276.     char subtitles_file[MAX_PATH];
  277.     FILE *indexf;
  278.  
  279.     if (strcmp(language, "en") == 0)
  280.     {    subtitles_available = -1;
  281.         return;        /* use default messages */
  282.     }
  283.  
  284.     buildfilename (subtitles_file, SUBTITLES_FILE);
  285.     if ((langf = fopenbin(subtitles_file, "r")) == NULL)
  286.     {
  287.         subtitles_available = -1;
  288.         return;
  289.     }
  290.     init_crc();
  291.     if ((strbuf = (char *) malloc(STRBUFSIZE)) == NULL)
  292.     {
  293.         fprintf(stderr, "Not enough memory for foreign subtitles\n");
  294.         fclose(langf);
  295.         subtitles_available = -1;
  296.         return;
  297.     }
  298.     buildfilename(indexfile, LANG_INDEXFILE);
  299.     if ((indexf = fopenbin(indexfile, "r")) != NULL)
  300.     {
  301.         if (fread(&indx_hdr, 1, sizeof(indx_hdr), indexf) == sizeof(indx_hdr) &&
  302.             indx_hdr.lang_fsize == fsize(langf) &&
  303.             strcmp(indx_hdr.lang, language) == 0)
  304.         {
  305.             nmsg = indx_hdr.nmsg;
  306.             indx_tbl = (struct indx_ent *) malloc(nmsg * sizeof(struct indx_ent));
  307.             if (indx_tbl == NULL)
  308.             {
  309.                 fprintf(stderr, "Not enough memory for foreign subtitles\n");
  310.                 fclose(indexf);
  311.                 fclose(langf);
  312.                 subtitles_available = -1;
  313.                 return;
  314.             }
  315.             if (fread(indx_tbl, sizeof(struct indx_ent), nmsg, indexf) != nmsg)
  316.             {
  317.                 free(indx_tbl);    /* create a new one */
  318.                 indx_tbl = NULL;
  319.             }
  320.         }
  321.         fclose(indexf);
  322.     }
  323.     if (indx_tbl == NULL && make_indexfile(indexfile) < 0)
  324.     {
  325.         fclose(langf);
  326.         subtitles_available = -1;
  327.     }
  328.     else
  329.         subtitles_available = 1;
  330. }
  331.  
  332.  
  333. static int
  334. make_indexfile(char *indexfile)
  335. {
  336.     FILE *indexf;
  337.     long filepos;
  338.     int total_msgs = 0;
  339.     char *res;
  340.  
  341.     if (verbose)    /* must be set in config.pgp */
  342.         fprintf(stderr, "Creating language index file '%s' for language \"%s\"\n",
  343.                 indexfile, language);
  344.     rewind(langf);
  345.     indx_hdr.lang_fsize = fsize(langf);
  346.     strncpy(indx_hdr.lang, language, 15);
  347.     init_crc();
  348.     line = 1;
  349.     nmsg = 0;
  350.     while (readstr(langf, strbuf, 0))
  351.     {
  352.         if (nmsg == max_msgs)
  353.         {
  354.             if (max_msgs)
  355.             {    max_msgs *= 2;
  356.                 indx_tbl = (struct indx_ent *) realloc(indx_tbl, max_msgs *
  357.                             sizeof(struct indx_ent));
  358.             }
  359.             else
  360.             {    max_msgs = 400;
  361.                 indx_tbl = (struct indx_ent *) malloc(max_msgs *
  362.                             sizeof(struct indx_ent));
  363.             }
  364.             if (indx_tbl == NULL)
  365.             {
  366.                 fprintf(stderr, "Not enough memory for foreign subtitles\n");
  367.                 return(-1);
  368.             }
  369.         }
  370.         ++total_msgs;
  371.         indx_tbl[nmsg].crc = message_crc(strbuf);
  372.         if (lookup_offset(indx_tbl[nmsg].crc) != -1)
  373.             fprintf(stderr, "language.txt:%d: Message CRC not unique: \"%s\"\n",
  374.                     line, strbuf);
  375.         do
  376.         {
  377.             filepos = ftell(langf);
  378.             res = readstr (langf, strbuf, 1);        /* Abort if find newline first */
  379.         } while (res && strbuf[0] != '\0' && strcmp(language, lang) != 0);
  380.  
  381.         if (res == NULL)
  382.             break;
  383.         if (strbuf[0] == '\0')    /* No translation */
  384.             continue;
  385.  
  386.         indx_tbl[nmsg].offset = filepos;
  387.         ++nmsg;
  388.         do
  389.             res = readstr (langf, strbuf, 1);        /* Abort if find newline first */
  390.         while (res && strbuf[0] != '\0');
  391.     }
  392.     line = 0;
  393.     indx_hdr.nmsg = nmsg;
  394.     if (nmsg == 0)
  395.     {    fprintf(stderr, "No translations available for language \"%s\"\n\n",
  396.                 language);
  397.         return(-1);
  398.     }
  399.     if (verbose || total_msgs != nmsg)
  400.         fprintf(stderr, "%d messages, %d translations\n\n", total_msgs, nmsg);
  401.  
  402.     if ((indexf = fopenbin(indexfile, "w")) == NULL)
  403.         fprintf(stderr, "Cannot create %s\n", indexfile);
  404.     else
  405.     {
  406.         fwrite(&indx_hdr, 1, sizeof(indx_hdr), indexf);
  407.         fwrite(indx_tbl, sizeof(struct indx_ent), nmsg, indexf);
  408.         if (ferror(indexf) || fclose(indexf))
  409.             fprintf(stderr, "error writing %s\n", indexfile);
  410.     }
  411.     return(0);
  412. }
  413. #endif /* TEST */
  414.